#include <sys/types.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <string.h>

#include "serialport.h"
#include "user.h"
SerialPort::SerialPort(Reactor *user_R,const char *dev_name,int baud_rate)
{
    reactor = user_R;
    #ifdef USEING_BUFFER
    recv_Buf = new Buffer(65535);
    #endif // USEING_BUFFER
    serial_fd = open(dev_name, O_RDWR | O_NOCTTY);
    if(serial_fd < 0)
	{
		printf("in SerialPort: open %s filed\n",dev_name);
	}
	else
	{
		printf("open %s  %d success\n",dev_name,serial_fd);

	}
    if(setConfig(baud_rate,8,'N',1) == 0)
    {
		printf("set %s Config success ,the baud_rate is %d \n",dev_name, baud_rate);
    }
}

SerialPort::~SerialPort()
{
    close(serial_fd);
}

int SerialPort::setConfig(int baudrate,char data_bits,char parity_bits,char stop_bits)
{
	int st_baud[]=
	{
		B4800,
		B9600,
		B19200,
		B38400,
		B57600,
		B115200,
		B230400,
		B1000000,
		B1152000,
		B3000000,
	};
	int std_rate[]=
	{
		4800,
		9600,
		19200,
		38400,
		57600,
		115200,
		230400,
		1000000,
		1152000,
		3000000,
	};

	int i,j;
	struct termios newtio, oldtio;
	/* save current port parameter */
	if (tcgetattr(serial_fd, &oldtio) != 0)
	{
		printf("%s,%d:ERROR\n",__func__,__LINE__);
		return -1;
	}
	bzero(&newtio, sizeof(newtio));

	/* config the size of char */
	newtio.c_cflag |= CLOCAL | CREAD;
	newtio.c_cflag &= ~CSIZE;

	/* config data bit */
	switch (data_bits)
	{
	case 7:
		newtio.c_cflag |= CS7;
		break;
	case 8:
		newtio.c_cflag |= CS8;
		break;
	}
	/* config the parity bit */
	switch (parity_bits)
	{
		/* odd */
	case 'O':
	case 'o':
		newtio.c_cflag |= PARENB;
		newtio.c_cflag |= PARODD;
		break;
		/* even */
	case 'E':
	case 'e':
		newtio.c_cflag |= PARENB;
		newtio.c_cflag &= ~PARODD;
		break;
		/* none */
	case 'N':
	case 'n':
		newtio.c_cflag &= ~PARENB;
		break;
	}
	/* config baudrate */
	j = sizeof(std_rate)/4;
	for(i = 0;i < j;i ++)
	{
		if(std_rate[i] == baudrate)
		{
			/* set standard baudrate */
			cfsetispeed(&newtio, st_baud[i]);
			cfsetospeed(&newtio, st_baud[i]);
			break;
		}
	}
	/* config stop bit */
    if( stop_bits == 1 )
       newtio.c_cflag &=  ~CSTOPB;
    else if ( stop_bits == 2 )
       newtio.c_cflag |=  CSTOPB;

    /* config waiting time & min number of char */
    newtio.c_cc[VTIME]  = 1;
    newtio.c_cc[VMIN] = 1;

    /* using the raw data mode */
    newtio.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);
    newtio.c_oflag  &= ~OPOST;

    /* flush the hardware fifo */
    tcflush(serial_fd,TCIFLUSH);

    /* activite the configuration */
    if((tcsetattr(serial_fd,TCSANOW,&newtio))!=0)
    {
    	printf("%s,%d:ERROR\n",__func__,__LINE__);
    	return -1;
    }
    return 0;
}


int SerialPort::Send(const char *buf, int len)
{
	return write(serial_fd,buf,len);
}

void SerialPort::readHandle(int fd)
{
	int saved = -1;
	char buf[MAX_MSGLEN] = {0};
	char *user_data = NULL;

	if( buf == NULL)
	{
		return ;
	}
	else
	{
        memset(buf,0,MAX_MSGLEN);
        saved = read(serial_fd,buf,MAX_MSGLEN);
        if(saved > 0)
        {

            #ifdef USEING_BUFFER
            //printf("new data fd: %d  data: %s\n",serial_fd, buf);
            if(recv_Buf->add(buf,saved))
            {
               while((user_data = recv_Buf->getframe(buf)) != NULL)
                {
                    userCallback(user_data);
                }
            }
            #else
            if(buf[0] == '$')
            {
                if(buf[strlen(buf) - 1] == '#')
                {
                    buf[strlen(buf) - 1] = '\0';
                    user_data = &buf[1];
                    userCallback(user_data);
                    return ;
                }
            }

            #endif // USEING_BUFFER
        }
	}
	return ;
}


